#include "basicStruct/basicString.h"
#include "cMalloc.h"


/**
 * @brief 获取实际结构体的长度 T = O(1)
 * @param inString 字符串
 * @return size_t
 */
size_t getLength(arrayChar chars)
{
	struct String *structCString = getPointString(chars);
	return structCString->length;
}

/**
 * @brief 获取实际结构体的未使用的空间 T = O(1)
 * @param inString 字符串
 * @return size_t
 */
size_t getFree(arrayChar chars)
{
	struct String *structCString = getPointString(chars);
	return structCString->free;
}

/**
 * @brief 判断是否为空串
 * @param chars 字符串
 * @return bool 类型
 */
int stringIsEmpty(arrayChar chars)
{
	return getLength(chars) ? 1 : 0;
}

/**
 * @brief 获取char *指向的结构体
 * @param chars char *
 * @return chars真实类型 -- 结构体String
 */
struct String *getPointString(arrayChar chars)
{
	return (void *)(chars - (sizeof(struct String)));
}

/**
 * @brief 新建一个String
 * @param inString 字符串
 * @param length 字符串长度
 * @return 新建立的string的char数组
 */
arrayChar newString(const void *init, size_t length)
{

	///@note 不能超过最大内存
	if (length >= maxBufferSize)
	{
		return NULL;
	}

	struct String *string;
	string = cMalloc(sizeof(struct String) + length + 1);

	///@note 分配内存失败
	if (string == NULL)
	{
		return NULL;
	}

	///@note 更新内存信息
	string->length = length;
	string->free = 0;
	if (length && init)
	{
		memcpy(string->buffer, init, length);
	}

	///@note 保持c语言风格结束符
	string->buffer[length] = '\0';
	return (char *)string->buffer;
}

/**
 * @brief 销毁字串串
 * @param chars 待销毁的char * 字符串
 */
void removeString(arrayChar chars)
{
	if (chars == NULL)
	{
		return;
	}
	cFree(chars - sizeof(struct String));
}

/**
 * @brief 销毁字符串未使用的空间
 * @param chars 待销毁的char * 字符串
 */
arrayChar removeStringFree(arrayChar chars)
{
	struct String *string = getPointString(chars);

	///@note 重新调整大小
	string = cReMalloc(string, sizeof(struct String) + string->length + 1);
	string->free = 0;
	return string->buffer;
}

/**
 * @brief 清空字串(懒清空)
 * @param chars 字符串
 */
void clearString(arrayChar chars)
{
	struct String *string = getPointString(chars);
	string->free += string->length;
	string->length = 0;
	string->buffer[0] = '\0';
}

/**
 * @brief 扩容字串空间
 * @param chars 待扩容的 char * 字符串
 * @param addLength 增加的长度
 * @return char *
 */
arrayChar extendedStringSpace(arrayChar chars, size_t addLength)
{
	size_t oldFree = getFree(chars);
	///@note 剩余未使用内存充足
	if (oldFree >= addLength)
	{
		return chars;
	}

	size_t oldLength = getLength(chars);
	struct String *oldString = getPointString(chars);
	size_t newLength = oldLength + addLength;

	///@brief 扩容机制:小于 maxBufferSize扩容两倍；大于maxBufferSize，在原有长度基础上增加maxBufferSize
	if (newLength < maxBufferSize)
	{
		newLength *= 2;
	}
	else
	{
		newLength += maxBufferSize;
	}

	///@note +1是放置结束符’/0‘
	struct String *newString = cReMalloc(oldString, sizeof(struct String) + newLength + 1);

	///@note 扩容失败
	if (newString == NULL)
	{
		return NULL;
	}

	///@note 更新长度
	newString->free = newLength - oldLength;
	return newString->buffer;
}

/**
 * @brief 拷贝input中的字符串到source中
 * @param source 源字串
 * @param input 拷贝后的字符串
 * @param length 长度
 * @return 源字符串（可能扩容源字符串）
 */
arrayChar copyString(arrayChar source, inputChar input, size_t length)
{
	struct String *string = getPointString(source);
	size_t totalSize = string->free + string->length;

	///@note 如果当前string内存空间的长度小于待 复制的长度将会进行一次扩容
	if (totalSize < length)
	{
		source = extendedStringSpace(source, length - string->length);
		if (source == NULL)
		{
			return NULL;
		}
		string = getPointString(source);
		totalSize = string->free + string->length;
	}

	///@note 内存拷贝
	memcpy(source, input, length);
	source[length] = '\0';
	string->length = length;
	string->free = totalSize - length;
	return source;
}

arrayChar appendString(arrayChar chars, const void *t, size_t length)
{
	///@note 扩充空间
	chars = extendedStringSpace(chars, length);
	if (chars == NULL)
	{
		return NULL;
	}

	///@note 获取字符串
	struct String *string = getPointString(chars);

	///@note 拷贝字符串 [chars + string->length]偏移到源字符串 ‘/0’的位置
	memcpy(chars + string->length, t, length);

	///@note 更新属性
	string->length = string->length + length;
	string->free = string->free - length;

	///@note 添加新结尾符号
	chars[string->length] = '\0';

	///@note 返回新 sds
	return chars;
}

int main()
{
	const char *info = "hello string";
	arrayChar string = newString(info, strlen(info));
	printf("1 %zu\n", getPointString(string)->length);
	printf("1 %zu\n", getPointString(string)->free);
	printf("1 %s\n\n", getPointString(string)->buffer);

	const char *copy = "hello copy string";
	string = copyString(string, copy, strlen(copy));
	printf("2 %zu\n", getPointString(string)->length);
	printf("2 %zu\n", getPointString(string)->free);
	printf("2 %s\n\n", getPointString(string)->buffer);

	const char *append = " hello append string";
	string = appendString(string, append, strlen(append));
	printf("2 %zu\n", getPointString(string)->length);
	printf("2 %zu\n", getPointString(string)->free);
	printf("2 %s\n\n", getPointString(string)->buffer);

	const char split[] = "hello";
	int count = 0;

	return 0;
}